use std::{collections::HashSet, path::PathBuf};

use bitflags::bitflags;
use clap::Parser;
use anyhow::Result;

bitflags! {
    #[derive(Clone, Copy, Debug)]
    struct Flags: u32 {
        const IMAGE = 0b0001;
        const TILESET = 0b0010;
        const ALL = 0xffff_ffff;
    }
}

impl ToString for Flags {
    fn to_string(&self) -> String {
        let mut result = String::new();
        if self.contains(Flags::IMAGE) {
            result.push('i');
        }
        if self.contains(Flags::TILESET) {
            result.push('t');
        }
        result
    }
}

#[derive(Parser)]
struct Cli {
    #[arg(help = "Tmx文件路径")]
    path: String,
    #[arg(long, help = "是否输出绝对路径，如果填写false也不一定会输出相对路径，而是输出Tmx里记录的路径", default_value_t = false)]
    absolute: bool,

    #[arg(short, long, help = "输出类型", default_value_t = Flags::ALL,  value_parser(flag_parser))]
    flags: Flags,
}

fn main() {
    let args = Cli::parse();
    let map = load_tmx(&args).expect("load tmx failed");
    let mut tileset_paths: HashSet<PathBuf> = HashSet::new();
    let mut image_paths: HashSet<PathBuf> = HashSet::new();
    for tileset in map.tilesets().iter() {
        if tileset.source != map.source {
            tileset_paths.insert(tileset.source.clone());
        }

        if let Some(ref image) = tileset.image {
            image_paths.insert(image.source.clone());
        }

        for (_, tile) in tileset.tiles() {
            if let Some(ref image) = tile.image {
                image_paths.insert(image.source.clone());
            }
        }
    }

    for layer in map.layers() {
        match layer.layer_type() {
            tiled::LayerType::Image(image_layer) => {
                if let Some(ref image) = image_layer.image {
                    image_paths.insert(image.source.clone());
                }
            },
            _ => {}
        }
    }

    if args.flags.contains(Flags::TILESET) {
        for path in tileset_paths.iter() {
            if args.absolute {
                println!("{}", path.canonicalize().unwrap().display());
            } else {
                println!("{}", path.display());
            }
        }
    }

    if args.flags.contains(Flags::IMAGE) {
        for path in image_paths.iter() {
            if args.absolute {
                println!("{}", path.canonicalize().unwrap().display());
            } else {
                println!("{}", path.display());
            }
        }
    }

}

fn load_tmx(cli:&Cli)->Result<tiled::Map>{
    let mut loader = tiled::Loader::new();
    let tmx = loader.load_tmx_map(&cli.path)?;
    Ok(tmx)
}

// 字符串解析为Flags，返回Flags
// i表示image，t表示tileset
// 例如：it -> Flags::IMAGE | Flags::TILESET
fn flag_parser(flags: &str) -> Result<Flags> {
    let mut result = Flags::empty();
    for c in flags.chars() {
        match c {
            'i' => result |= Flags::IMAGE,
            't' => result |= Flags::TILESET,
            _ => return Err(anyhow::anyhow!("invalid flag: {}", c)),
        }
    }
    Ok(result)
}
